#include "VSSpatial.h"
#include "VSController.h"
#include "VSRenderer.h"
#include "VSGeometry.h"
#include "VSNode.h"
#include "VSGraphicInclude.h"
#include "VSStream.h"
using namespace VSEngine2;
IMPLEMENT_RTTI_NoCreateFun(VSSpatial,VSAVObject)
IMPLEMENT_INITIAL_NO_CLASS_FACTORY_BEGIN(VSSpatial)
IMPLEMENT_INITIAL_NO_CLASS_FACTORY_END
BEGIN_ADD_PROPERTY(VSSpatial,VSAVObject)
REGISTER_PROPERTY(m_WorldBV,WorldBV,VSProperty::F_SAVE_LOAD_CLONE);
REGISTER_PROPERTY(m_pMaterialInstance,MaterialInstance,VSProperty::F_SAVE_LOAD_CLONE);
REGISTER_PROPERTY(m_pLight,Light,VSProperty::F_SAVE_LOAD_CLONE);
REGISTER_PROPERTY(m_pCamera,Camera,VSProperty::F_SAVE_LOAD_CLONE);
REGISTER_PROPERTY(m_uiCullMode,CullMode,VSProperty::F_SAVE_LOAD_CLONE);
END_ADD_PROPERTY
VSSpatial::VSSpatial()
{
	

	m_uiCullMode = CM_DYNAMIC;
	m_pCamera.Clear();
	m_pLight.Clear();
	m_bIsVisibleUpdate = false;
	m_bIsNeedDraw = false;
	m_uiCurUseMaterial = 0;

}
VSSpatial::~VSSpatial()
{

	m_pMaterialInstance.Clear();
/*	m_VisibleInCuller.Clear();*/
	m_pCamera.Clear();
	m_pLight.Clear();
}

void VSSpatial::UpdateBV(double dAppTime)
{

	UpdateWorldBound(dAppTime);
	PropagateBoundToRoot(dAppTime); 

}
void VSSpatial::PropagateBoundToRoot(double dAppTime) 
{ 
	if ( m_pParent ) 
	{   
		((VSSpatial *)m_pParent)->UpdateBV(dAppTime);
		
	} 
} 



void VSSpatial::UpdateAll(double dAppTime)
{
	if(!m_bEnable)
		return ;
	UpdateNodeAll(dAppTime);


	if(m_bIsChanged)
	{
		
		PropagateBoundToRoot(dAppTime); 
	}
	m_bIsChanged = false;
	if (m_bIsVisibleUpdate)
	{
		m_bEnable = false;
	}

}
void VSSpatial::ComputeVisibleSet(VSCuller & Culler,bool bNoCull,double dAppTime)
{
	if(!m_bEnable && !m_bIsVisibleUpdate)
		return ;
	if(m_uiCullMode == CM_ALAWAYS)
		return ;
	if(m_uiCullMode == CM_NEVER)
		bNoCull = true;
/*	m_VisibleInCuller.Clear();*/
	unsigned int uiSavePlaneState = Culler.GetPlaneState();
	if(bNoCull)
	{
		ComputeNodeVisibleSet(Culler,bNoCull,dAppTime);
		if (m_bIsVisibleUpdate)
		{
			m_bEnable = true;
		}
	}
	else
	{
		unsigned int uiVSF = Culler.IsVisible(m_WorldBV);
		if (uiVSF == VSCuller::VSF_ALL)
		{
			bNoCull = true;
			ComputeNodeVisibleSet(Culler,bNoCull,dAppTime);
			if (m_bIsVisibleUpdate)
			{
				m_bEnable = true;
			}
		}
		else if (uiVSF == VSCuller::VSF_PARTIAL)
		{
			ComputeNodeVisibleSet(Culler,bNoCull,dAppTime);
			if (m_bIsVisibleUpdate)
			{
				m_bEnable = true;
			}
		}
		
	}
	Culler.SetPlaneState(uiSavePlaneState);

}

void VSSpatial::UpdateLightAll(double dAppTime)
{
	for(unsigned int i = 0 ; i < m_pLight.GetNum() ; i++)
	{
		if(m_pLight[i])
		{
			
			m_pLight[i]->UpdateAll(dAppTime);
		}
	}

}
void VSSpatial::UpdateCameraAll(double dAppTime)
{
	for(unsigned int i = 0 ; i < m_pCamera.GetNum() ; i++)
	{
		if(m_pCamera[i])
		{
			m_pCamera[i]->UpdateAll(dAppTime);
		}
	}

}
unsigned int VSSpatial::DiskUse()const
{
	unsigned int Used = VSAVObject::DiskUse();

	Used += sizeof(VSAABB3);

	// to remove 
	Used += sizeof(unsigned int);

	
	Used += sizeof(unsigned int);

	Used += sizeof(VSMaterialInstance *) * m_pMaterialInstance.GetNum();

	

	Used += m_pLight.GetNum() * sizeof(VSLight *);

	Used += m_pCamera.GetNum() * sizeof(VSCamera *);

	Used += sizeof(unsigned int) * 2;
	Used += sizeof(unsigned int);
	

	return Used;
}
bool VSSpatial::Save(VSStream & rStream,unsigned int &iSaveUse)const
{
	if(!VSAVObject::Save(rStream,iSaveUse))
		return 0;
	

	if(!rStream.Write(&m_WorldBV,sizeof(VSAABB3)))
		return 0;
	iSaveUse += sizeof(VSAABB3);


	// to remove
	iSaveUse += sizeof(unsigned int);


	unsigned int uiMaterialInstanceNum = m_pMaterialInstance.GetNum();
	if(!rStream.Write(&uiMaterialInstanceNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	for (unsigned int i =0 ; i < m_pMaterialInstance.GetNum() ;i++)
	{
		if(!rStream.WriteObjectPtr(m_pMaterialInstance[i]))
			return 0;
		iSaveUse += sizeof(VSMaterialInstance *);
	}
	

	unsigned int uiLightNum = m_pLight.GetNum();
	if(!rStream.Write(&uiLightNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	for (unsigned int i = 0 ; i < uiLightNum ; i++)
	{
		VSLight * pLight = m_pLight[i];
		if(!rStream.WriteObjectPtr(m_pLight[i]))
			return 0;
		iSaveUse += sizeof(VSLight *);
	}

	unsigned int uiCameraNum = m_pCamera.GetNum();
	if(!rStream.Write(&uiCameraNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	for (unsigned int i = 0 ; i < uiCameraNum ; i++)
	{

		if(!rStream.WriteObjectPtr(m_pCamera[i]))
			return 0;
		iSaveUse += sizeof(VSCamera *);
	}


	if(!rStream.Write(&m_uiCullMode,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	

	return 1;
}
bool VSSpatial::Load(VSStream & rStream,unsigned int &iSaveUse)
{
	if(!VSAVObject::Load(rStream,iSaveUse))
		return 0;


	if(!rStream.Read(&m_WorldBV,sizeof(VSAABB3)))
		return 0;
	iSaveUse += sizeof(VSAABB3);

	// to remove
	unsigned int uiMaterialNum = 0;
	if(!rStream.Read(&uiMaterialNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);
	
	


	unsigned int uiMaterialInstanceNum = 0;
	if(!rStream.Read(&uiMaterialInstanceNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);
	m_pMaterialInstance.SetBufferNum(uiMaterialInstanceNum);

	for (unsigned int i = 0 ; i < m_pMaterialInstance.GetNum() ;i++)
	{
		if(!rStream.ReadObjectPtr(m_pMaterialInstance[i]))
			return 0;
		iSaveUse += sizeof(VSMaterialInstance *);	
	}

	unsigned int uiLightNum = 0;
	if(!rStream.Read(&uiLightNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	m_pLight.SetBufferNum(uiLightNum);
	for (unsigned int i = 0 ; i < uiLightNum ; i++)
	{

		if(!rStream.ReadObjectPtr(m_pLight[i]))
			return 0;
		iSaveUse += sizeof(VSLight *);
	}

	unsigned int uiCameraNum = 0;
	if(!rStream.Read(&uiCameraNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	m_pCamera.SetBufferNum(uiCameraNum);

	for (unsigned int i = 0 ; i < uiCameraNum ; i++)
	{

		if(!rStream.ReadObjectPtr(m_pCamera[i]))
			return 0;
		iSaveUse += sizeof(VSCamera *);
	}




	if(!rStream.Read(&m_uiCullMode,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	

	return 1;
}
bool VSSpatial::Link(VSStream & rStream)
{
	if(!VSAVObject::Link(rStream))
		return 0;

	for (unsigned int i = 0 ; i < m_pMaterialInstance.GetNum() ;i++)
	{

		rStream.LinkObjectPtr(m_pMaterialInstance[i]);
	}
	
	for (unsigned int i = 0 ; i < m_pLight.GetNum() ; i++)
	{

		rStream.LinkObjectPtr(m_pLight[i]);
	}

	for (unsigned int i = 0 ; i < m_pCamera.GetNum() ; i++)
	{
		rStream.LinkObjectPtr(m_pCamera[i]);
	}


	return 1;

}
bool VSSpatial::Clone(const VSObject *pObject,unsigned int uiType)
{
	const VSSpatial* Temp = DynamicCast<VSSpatial>(pObject); 
	if(!Temp)
		return 0;
	if(VSAVObject::Clone(pObject,uiType))
	{	
		m_WorldBV = Temp->m_WorldBV;
		m_pLight.SetBufferNum(Temp->m_pLight.GetNum());
		m_pCamera.SetBufferNum(Temp->m_pCamera.GetNum());
		m_uiCullMode = Temp->m_uiCullMode;				
		m_bIsVisibleUpdate = Temp->m_bIsVisibleUpdate;
		m_bIsNeedDraw = Temp->m_bIsNeedDraw;
										
		
		for (unsigned int i = 0 ; i < Temp->m_pMaterialInstance.GetNum() ;i++)
		{
			AddMaterialInstance(Temp->m_pMaterialInstance[i]);
			
		}
		
		for (unsigned int i = 0 ; i < m_pLight.GetNum() ; i++)
		{
			VSLight * pTemp1  = Temp->m_pLight[i];
			VSLight * pTemp2 =(VSLight *)VSObject::GetInstance((pTemp1)->GetType().GetName());
			pTemp2->Clone(pTemp1,uiType);
			m_pLight[i]= pTemp2;
		}
		for (unsigned int i = 0 ; i < m_pCamera.GetNum() ; i++)
		{
			VSCamera * pTemp1  = Temp->m_pCamera[i];
			VSCamera * pTemp2 =(VSCamera *)VSObject::GetInstance((pTemp1)->GetType().GetName());
			pTemp2->Clone(pTemp1,uiType);
			m_pCamera[i]= pTemp2;
		}
		
		return 1;
	}
	else
	{
		return 0;

	}

}
bool VSSpatial::Register(VSStream & rStream)const
{
	if (rStream.IsObjectRegister(this))
	{
		return 1;
	}
	if(!VSAVObject::Register(rStream))
		return 0;

	for (unsigned int i = 0 ;i < m_pMaterialInstance.GetNum() ;i++)
	{
		if(m_pMaterialInstance[i])
		{
			if(!m_pMaterialInstance[i]->Register(rStream))
				return 0;
		}
	}
	for (unsigned int i = 0 ;i < m_pLight.GetNum() ;i++)
	{
		if(m_pLight[i])
		{
			if(!m_pLight[i]->Register(rStream))
				return 0;
		}
	}		

	for (unsigned int i = 0 ;i < m_pCamera.GetNum() ;i++)
	{
		if(m_pCamera[i])
		{
			if(!m_pCamera[i]->Register(rStream))
				return 0;
		}
	}	
	return 1;
}
bool VSSpatial::SetLodDesirePercent(VSREAL fDesirePercent)
{
	if (fDesirePercent > 1.0f || fDesirePercent < 0.0f)
	{
		return false;
	}
	return true;
}
void VSSpatial::UpDateView(VSCuller & Culler,double dAppTime)
{
}
void VSSpatial::SetIsVisibleUpdate(bool bIsVisibleUpdate)
{
	m_bIsVisibleUpdate = bIsVisibleUpdate;
}
